package com.jet.goods.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jet.core.exception.CustomException;
import com.jet.core.model.vo.PageVo;
import com.jet.core.utils.IdUtil;
import com.jet.goods.domain.dto.SpecDto;
import com.jet.goods.domain.dto.SpecValueDto;
import com.jet.goods.domain.entity.GoodsSkuSpec;
import com.jet.goods.domain.entity.GoodsSpec;
import com.jet.goods.domain.query.SpecKeyQuery;
import com.jet.goods.domain.vo.SpecKeyVo;
import com.jet.goods.domain.vo.SpecValueVo;
import com.jet.goods.mapper.GoodsSpecMapper;
import com.jet.goods.service.IGoodsSkuSpecService;
import com.jet.goods.service.IGoodsSpecService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author author
 * @since 2025-03-04
 */
@Service
public class GoodsSpecServiceImpl extends ServiceImpl<GoodsSpecMapper, GoodsSpec> implements IGoodsSpecService {

    private final IGoodsSkuSpecService goodsSkuSpecService;

    public GoodsSpecServiceImpl(IGoodsSkuSpecService goodsSkuSpecService) {
        this.goodsSkuSpecService = goodsSkuSpecService;
    }

    @Override
    public GoodsSpec create(long merchantNo, SpecDto dto) {
        GoodsSpec specEntity = findChildByName(merchantNo, dto.getName(), dto.getPid());
        if (specEntity != null) {
            if (StrUtil.isBlank(dto.getPid())) {
                throw new CustomException("规格项重复");
            }
            throw new CustomException("规格值重复");
        }
        GoodsSpec entity = new GoodsSpec();
        entity.setId(IdUtil.generateLower());
        entity.setMerchantNo(merchantNo);
        entity.setName(dto.getName().trim());
        entity.setPid(dto.getPid());
        super.save(entity);
        return entity;
    }

    @Override
    public void edit(long merchantNo, String id, SpecDto dto) {
        GoodsSpec entity = super.getById(id);
        if (entity == null) {
            return;
        }
        GoodsSpec specEntity = findChildByName(merchantNo, dto.getName(), dto.getPid());
        if (specEntity != null && !specEntity.getId().equals(id)) {
            if (StrUtil.isBlank(dto.getPid())) {
                throw new CustomException("规格项重复");
            }
            throw new CustomException("规格值重复");
        }
        entity.setId(id);
        entity.setMerchantNo(merchantNo);
        entity.setName(dto.getName());
        entity.setPid(dto.getPid());
        super.updateById(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchEdit(long merchantNo, List<SpecValueDto> dtos) {
        dtos.forEach(x -> {
            SpecDto specDto = new SpecDto();
            specDto.setName(x.getName());
            specDto.setPid(x.getPid());
            if (StrUtil.isBlank(x.getId())) {
                create(merchantNo, specDto);
            } else {
                edit(merchantNo, x.getId(), specDto);
            }
        });
    }

    @Override
    public void delete(long merchantNo, String id) {
        List<GoodsSkuSpec> list = goodsSkuSpecService.findAllBySpecId(id);
        if (!CollectionUtils.isEmpty(list)) {
            throw new CustomException("无法删除使用中的规格");
        }
        super.removeById(id);
    }

    @Override
    public GoodsSpec findChildByName(long merchantNo, String name, String pid) {
        QueryWrapper<GoodsSpec> wrapper = new QueryWrapper<>();
        wrapper.eq("1", 1);
        wrapper.and(x -> x.eq("merchant_no", 0).or().eq("merchant_no", merchantNo))
                .eq("name", name);
        if (StrUtil.isBlank(pid)) {
            wrapper.isNull("pid");
        } else {
            wrapper.eq("pid", pid);
        }

        return super.getOne(wrapper);
    }

    @Override
    public List<GoodsSpec> findAllByIds(long merchantNo, List<String> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return super.listByIds(ids);
    }

    @Override
    public List<GoodsSpec> findAll(long merchantNo, SpecKeyQuery query) {
        QueryWrapper<GoodsSpec> wrapper = new QueryWrapper<>();
        wrapper.eq("1", 1);
        wrapper.and(x -> x.eq("merchant_no", 0).or().eq("merchant_no", merchantNo));
        if (StrUtil.isBlank(query.getPid())) {
            wrapper.and(x -> x.isNull("pid").or().eq("pid", ""));
        } else {
            wrapper.eq("pid", query.getPid());
        }
        if (StrUtil.isNotBlank(query.getSearchKey())) {
            wrapper.like("name", query.getSearchKey());
        }
        wrapper.orderByAsc("update_time");
        return super.list(wrapper);
    }

    @Override
    public PageVo<SpecKeyVo> page(long merchantNo, SpecKeyQuery query) {
        Page<GoodsSpec> tempQuery = new Page<>(query.getPageIndex(), query.getPageSize());
        QueryWrapper<GoodsSpec> wrapper = new QueryWrapper<>();
        wrapper.eq("1", 1);
        wrapper.lambda().and(x -> x.eq(GoodsSpec::getMerchantNo, 0).or().eq(GoodsSpec::getMerchantNo, merchantNo))
                .and(x -> x.isNull(GoodsSpec::getPid).or().eq(GoodsSpec::getPid, ""))
                .like(StrUtil.isNotBlank(query.getSearchKey()), GoodsSpec::getName, query.getSearchKey())
                .orderByDesc(GoodsSpec::getCreateTime);
        IPage<GoodsSpec> page = super.page(tempQuery, wrapper);
        List<SpecKeyVo> keyVos = page.getRecords().stream().map(x -> {
            SpecKeyVo keyVo = new SpecKeyVo();
            BeanUtils.copyProperties(x, keyVo);

            QueryWrapper<GoodsSpec> subWrapper = new QueryWrapper<>();
            subWrapper.eq("1", 1);
            subWrapper.lambda().and(y -> y.eq(GoodsSpec::getMerchantNo, 0).or().eq(GoodsSpec::getMerchantNo, merchantNo))
                    .eq(GoodsSpec::getPid, x.getId());
            List<GoodsSpec> values = super.list(subWrapper);
            List<SpecValueVo> valueVos = values.stream().map(y -> {
                SpecValueVo valueVo = new SpecValueVo();
                BeanUtils.copyProperties(y, valueVo);
                return valueVo;
            }).collect(Collectors.toList());
            keyVo.setValues(valueVos);
            return keyVo;
        }).collect(Collectors.toList());
        return PageVo.result(page, keyVos);
    }
}
